/* $$Id: RssFeedOpen.java 31 2008-01-09 15:22:49Z qxodream $$
 *
 * RssReaderMidlet --  RSS reader for J2ME(midp)
 * The original codes of this porgram is from
 * RssOwlMIDlet(zhengyun@gmail.com)
 *
 * Copyright (c) 2007-2008 QXO(qxodream@gmail.com)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package com.ultrapower.view;

import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import javax.microedition.lcdui.TextField;

import com.ultrapower.control.GUIController;
import com.ultrapower.model.RssFeed;
import com.ultrapower.model.RssFeedParser;
import com.ultrapower.model.RssItem;
import com.ultrapower.tools.ResUtils;

/**
 * 类说明：“读取Rss Feed新闻”的Form界面 显示当前选中的Rss Feed的新闻列表,以新闻条目主题列表方式显示。<br/>提供菜单命令有：
 * 读取新闻 添加书签 编辑书签 删除书签 关于我
 *
 * @author zhengyun@ultrapower 2005.10.07
 * @author QXO(qxodream@gmail.com)
 *
 */
public class RssFeedOpen extends Form implements Runnable {
	private GUIController controller;
	private Display m_display; // The display for this MIDlet
	private Command m_openHeaderCmd; // The open header command
	private Command m_backHeaderCmd; // The back to bookmark list command
	private Command m_updateCmd; // The update headers command
	private TextField errorTextField;

	private boolean m_getPage; // The noticy flag for HTTP
	private List m_headerList; // The header list
	private RssFeedParser m_curRssParser; // The currently selected RSS

	private Thread m_netThread; // The thread for networking
	private static Image m_iconOpen = ResUtils
			.getImage(ResUtils.IMG_UNREADFEED);
	private static Image m_iconError = ResUtils
			.getImage(ResUtils.IMG_ERROR);
	private int m_nErrorTextFieldId;
	private int m_nErrorImageFieldId;
	private WaitFlash m_WaitFlash;

	/***************************************************************************
	 * // RssFeedOpen::RssFeedOpen // // Description: // 初始化界面: 初始化菜单命令;
	 * 初始化新闻条目列表; 本Form其实也是一个Thread,我们为了让后台来获取并解析RSS XML,所以启动线程 加载图像 // //
	 * Parameters: // Return Values: // Remark: // Author: //
	 * zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public RssFeedOpen(String title, GUIController control) {
		super(title);
		controller = control;
		m_nErrorTextFieldId = -1;
		m_nErrorImageFieldId = -1;
		m_display = controller.rssMidlet.getCurrentDisplay();

		m_openHeaderCmd = new Command(ResUtils
				.getLabel(ResUtils.KEY_VIEW_DETAIL), Command.SCREEN, 1);
		m_backHeaderCmd = new Command(ResUtils
				.getLabel(ResUtils.CMD_BACK), Command.BACK, 1);
		m_updateCmd = new Command(ResUtils
				.getLabel(ResUtils.TXT_CMD_UPDATENEWS), Command.SCREEN, 2);
		initializeHeadersList();

		this.setCommandListener(new RssFeedOpenListener());

		/** Initialize thread for http connection operations */
		m_netThread = new Thread(this);
		m_netThread.start();
	}

	/***************************************************************************
	 * // RssFeedOpen::updateHeaders // // Description: // 更新新闻条目列表:
	 * 先将当前新闻列表全部删除 再告诉后台线程,可以去读取并解析RSS Feed了 // // Parameters: // Return
	 * Values: // Remark: // Author: // zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public void updateHeaders() {
		System.out.println("/** updateHeaders */");

		// 将当前新闻列表全部删除
		deleteAll();
		if (m_WaitFlash == null) {
			// 当前没有等候动画时,我们需要创建一个
			m_WaitFlash = new WaitFlash();
			m_WaitFlash.setMessage(ResUtils.getLabel(ResUtils.FEED_READING_MSG));
			m_display.setCurrent(m_WaitFlash);
		} else {
			m_display.setCurrent(m_WaitFlash);
		}
		System.out.println("设置了等待画面!");
		if (m_curRssParser.getRssFeed().getUrl().length() > 0) {
			m_getPage = true;
		}
	}

	/***************************************************************************
	 * // RssFeedOpen::deleteAll // // Description: // 将当前新闻列表全部删除 // //
	 * Parameters: // Return Values: // Remark: 由于MIDP
	 * 2.0中才定义了List的deleteAll()方法, 但是MIDP1.0中List支持delete(int itemNum).
	 * 所以在MIDP1.0中,可以使用List的size()得到当前List中的Item的数量, 然后使用for循环delete(int
	 * itemNum),这样在MIDP1.0中实现deleteAll的功能。
	 * 但这么for循环删除有一个非常奇怪的地方,好像是隔一个删一个，导致无法删除干净?!
	 * 所以最后不得不采用while循环删除第一个元素的办法!这也许是一个MIDP1.0的bug。 // Author: //
	 * zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public synchronized void deleteAll() {
		System.out.println("!-- RssFeedOpen::Enter deleteAll --!");

		// 下面的删除代码只能隔一个删一个m_headerList的元素，导致无法删除干净
		/*
		 * for(int i = 0;i < m_headerList.size();i++){
		 *
		 * m_headerList.delete(i); System.out.println("delete>>" + i); }
		 */

		// 这样才能完全删除:
		while (m_headerList.size() > 0)
			m_headerList.delete(0);
	}

	/***************************************************************************
	 * // RssFeedOpen::appendRssItem // // Description: // 向List中添加Rss Item // //
	 * Parameters: // Return Values: // Remark: // Author: //
	 * zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public void appendRssItem(String title) {
		setCurrentDispalyToHeaderList();
		int nId = m_headerList.append(title, m_iconOpen);
		System.out.println("/** appendRssItem:append item id=" + nId);
	}

	/***************************************************************************
	 * // RssFeedOpen::setRss // // Description: // 设置当前需要去读取哪一个Rss Feed // //
	 * Parameters: feed: 输入feed // Return Values: // Remark: // Author: //
	 * zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public void setRss(RssFeed feed) {
		m_curRssParser = new RssFeedParser(feed, controller);

		m_curRssParser.openForm = this;

		if (m_curRssParser.getRssFeed().getItems().size() == 0) {

			/** Update RSS feed headers only if this is a first time */
			updateHeaders();
		} else {
			System.out.println("/** fillHeadersList */");
			/**
			 * Show currently selected RSS feed headers without updating them
			 */
			fillHeadersList();
		}
	}

	/***************************************************************************
	 * // RssFeedOpen::fillHeadersList // // Description: // 根据当前Rss
	 * Feed对应的类实体中存储的Rss Item列表，重新填充界面上的List // // Parameters: // Return Values: //
	 * Remark: // Author: // zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	private void fillHeadersList() {
		System.out.println("/** Enter fillHeadersList */");
		deleteAll();

		RssFeed feed = m_curRssParser.getRssFeed();
		System.out.println("重新采用RssFeed:" + feed.getName());
		for (int i = 0; i < m_curRssParser.getRssFeed().getItems().size(); i++) {

			RssItem r = (RssItem) feed.getItems().elementAt(i);
			m_headerList.append(r.getTitle(), m_iconOpen);
		}
		// 一定要在重置了新闻列表后,把m_headerList设置为焦点,否则屏幕上会没有效果!
		setCurrentDispalyToHeaderList();
	}

	/***************************************************************************
	 * // RssFeedOpen::initializeHeadersList // // Description: // Initialize
	 * RSS headers list // // Parameters: // Return Values: // Remark: //
	 * Author: // zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	private void initializeHeadersList() {
		System.out.println("/** Enter initializeHeadersList */");
		m_headerList = new List(ResUtils
				.getFormTitle(ResUtils.KEY_READ_FEED), List.IMPLICIT);
		m_headerList.addCommand(m_openHeaderCmd);
		m_headerList.addCommand(m_backHeaderCmd);
		m_headerList.addCommand(m_updateCmd);
		m_headerList.setCommandListener(new RssFeedOpenListener());
	}

	/***************************************************************************
	 * // RssFeedOpen::run // // Description: // Run method is used to get RSS
	 * feed with HttpConnection // // Parameters: // Return Values: // Remark: //
	 * Author: // zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public void run() {
		/* Use networking if necessary */
		long lngStart;
		long lngTimeTaken;
		while (true) {
			try {
				// 我们是依靠m_getPage来判断是否去得到并解析Rss XML的.
				// 如果当前m_getPage是false,那么本线程就只能先睡眠一段时间了.
				if (m_getPage) {
					try {
						if (m_nErrorTextFieldId > 0) {
							this.delete(m_nErrorTextFieldId);
						}
						if (m_nErrorImageFieldId > 0) {
							this.delete(m_nErrorImageFieldId);
						}
						/** Get RSS feed */
						System.out
								.println("/** m_curRssParser.parseRssFeed(); */");
						if (m_curRssParser.parseRssFeed())
							setCurrentDispalyToHeaderList();
						else {
							this.addCommand(m_backHeaderCmd);

							m_WaitFlash = null;
						}
					} catch (Exception e) {
						/** Error while parsing RSS feed */
						System.out.println("Error: " + e.getMessage());

						errorTextField = new TextField("RSS提示信息 : "
								+ e.getMessage(), "\n无法解析Rss Feed:\n"
								+ m_curRssParser.getRssFeed().getUrl(), 64,
								TextField.ANY);
						this.addCommand(m_backHeaderCmd);

						// 在添加元素到界面上时,必须记下插入的id,这样下次解析RssFeed
						// 时就可以先行删除这些元素了,不至于造成重复插入
						m_nErrorImageFieldId = this.append(m_iconError);
						m_nErrorTextFieldId = this.append(errorTextField);
						m_display.setCurrent(this);
						m_WaitFlash = null;

					}
					m_getPage = false;
				}
				lngStart = System.currentTimeMillis();
				lngTimeTaken = System.currentTimeMillis() - lngStart;
				if (lngTimeTaken < 100)
					Thread.sleep(75 - lngTimeTaken);
			} catch (InterruptedException e) {
				break;
			}
		}
	}

	/***************************************************************************
	 * // RssFeedOpen::setCurrentDispalyToHeaderList // // Description: //
	 * 设置画面到Header List // // Parameters: // Return Values: // Remark: //
	 * Author: // zhengyun@ultrapower 2005.10.07 //
	 **************************************************************************/
	public void setCurrentDispalyToHeaderList() {
		System.out.println("设置画面到Header List!");
		m_display.setCurrent(m_headerList);
		if (m_WaitFlash != null) {
			// 销毁等候动画Form
			m_WaitFlash = null;
		}
	}

	/*
	 * 内部监听器，监听器监听所有Command事件，并把事件响应推出来让控制器处理
	 */
	private class RssFeedOpenListener implements CommandListener {
		public void commandAction(Command command, Displayable disp) {
			if (command == m_backHeaderCmd) {
				System.out.println("Back Menu!");
				controller.handleEvent(GUIController.EventID.EVENT_VIEW_BACK,
						null);
			} else if (command == m_openHeaderCmd
					|| (command == List.SELECT_COMMAND && m_display
							.getCurrent() == m_headerList)) {
				int ind = ((List) disp).getSelectedIndex();
				if (ind == -1)
					return;
				Object[] args = { m_curRssParser.getRssFeed().getItems()
						.elementAt(ind) };
				controller.handleEvent(
						GUIController.EventID.EVENT_VIEW_RSS_ITEM, args);
			} else if (command == m_updateCmd) {
				int ind = ((List) disp).getSelectedIndex();
				if (ind == -1)
					return;
				Object[] args = { m_curRssParser.getRssFeed().getItems()
						.elementAt(ind) };
				controller.handleEvent(
						GUIController.EventID.EVENT_UPDATE_RSS_ITEMS, args);
			}
		}
	}// end inner class
}
